package es.unex.meigas.gvsig.core;

import java.awt.geom.Rectangle2D;

import org.cresques.cts.IProjection;
import org.cresques.io.data.Grid;
import org.cresques.io.data.RasterBuf;

import com.iver.cit.gvsig.fmap.layers.FLyrRaster;

import es.unex.meigas.dataObjects.AbstractRasterLayer;
import es.unex.meigas.dataObjects.IRasterLayer;
import es.unex.meigas.rasterWrappers.GridExtent;

public class gvRasterLayer extends AbstractRasterLayer {

	private double DEFAULT_NO_DATA_VALUE = -99999.;

	private String m_sFilename;
	private IProjection m_Projection;
	//private double m_dNoDataValue = DEFAULT_NO_DATA_VALUE;

	public void create(String sName, String sFilename,
						GridExtent ge, int iDataType,
						int iNumBands, Object crs) {

		RasterMemoryDriver rmd = new RasterMemoryDriver(ge, iDataType, iNumBands);
		rmd.setName(sName);
		rmd.setProjection((IProjection) crs);
		rmd.setNoDataValue(DEFAULT_NO_DATA_VALUE);

		m_BaseDataObject = rmd;

		m_sFilename = sFilename;

		m_Projection = (IProjection) crs;

	}

	public void create(String sName, String sFilename,
			GridExtent ge, int iDataType, Object crs) {

		create(sName, sFilename, ge, iDataType, 1, crs);

	}

	public void create(Object obj) {

		if (obj instanceof FLyrRaster){
			m_BaseDataObject = obj;
			m_Projection = ((FLyrRaster)obj).getProjection();
		}

	}

	public int getDataType() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			return layer.getGrid().getDataType();
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getDataType();
		}

		return 0;
	}

	public void assign(double dValue) {

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			super.assign(dValue);
		}

	}

	public void assign(IRasterLayer layer) {

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			super.assign(layer);
		}

	}

	public void setCellValue(int x, int y, int iBand, double dValue) {

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			layer.setCellValue(x,y, iBand, dValue);
		}

	}

	public void setNoDataValue(double dNoDataValue) {

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			layer.setNoDataValue(dNoDataValue);
		}
		else if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			layer.getGrid().setNoDataValue(dNoDataValue);
		}

	}

	public void setNoData(int x, int y) {

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			layer.setNoData(x, y);
		}

	}

	public double getNoDataValue(){

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getNoDataValue();
		}
		else if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			return layer.getGrid().getNoDataValue();
		}

		return 0;

	}

	public double getCellValueInLayerCoords(int x, int y, int band) {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			Grid grid = layer.getGrid();
			int iType = grid.getDataType();

			if (iType == RasterBuf.TYPE_DOUBLE) {
				return  grid.getRasterBuf().getElemDouble(y, x, band);
			} else if (iType == RasterBuf.TYPE_INT) {
				return (double)  grid.getRasterBuf().getElemInt(y, x, band);
			} else if (iType == RasterBuf.TYPE_FLOAT) {
				return (double)  grid.getRasterBuf().getElemFloat(y, x, band);
			} else if (iType == RasterBuf.TYPE_BYTE) {
				return (double) ( grid.getRasterBuf().getElemByte(y, x, band) & 0xff);
			} else if ((iType == RasterBuf.TYPE_SHORT) | (iType == RasterBuf.TYPE_USHORT)) {
				return (double)  grid.getRasterBuf().getElemShort(y, x, band);
			}

			return grid.getNoDataValue();
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getCellValue(x, y, band);
		}

		return getNoDataValue();

	}

	public int getBandsCount() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			return layer.getSource().getNumBands();
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getBandCount();
		}

		return 0;

	}

	public void fitToGridExtent(GridExtent ge){

		int iNX, iNY;
		int x, y;
		int iBand;

		if (ge != null){
			if (!ge.equals(getWindowGridExtent()) ){
				if (m_BaseDataObject instanceof RasterMemoryDriver) {
					RasterMemoryDriver gvSIGDriver = (RasterMemoryDriver) m_BaseDataObject;

					FLyrRaster gvSIGLayer = gvSIGDriver.getRasterLayer(Long.toString(System.currentTimeMillis()).toString(),
							m_Projection);
					gvRasterLayer orgLayer = new gvRasterLayer();
					orgLayer.create(gvSIGLayer);

					iNX = ge.getNX();
					iNY = ge.getNY();

					m_BaseDataObject = null;

					create(this.getName(), m_sFilename, ge, this.getDataType(), this.getBandsCount(), gvSIGDriver.getProjection());
					for (iBand = 0; iBand < this.getBandsCount(); iBand++){
						for (y = 0; y < iNY; y++){
							for (x = 0; x < iNX; x++){
								setCellValue(x, y, iBand, orgLayer.getCellValueAsDouble(x, y, iBand));
							}
						}
					}
				}
			}
		}
	}

	public String getName() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			return layer.getName();
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getName();
		}

		return null;

	}

	public void postProcess() {

		if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			if (layer.export(m_sFilename, m_Projection)){
				FLyrRaster rasterLayer = (FLyrRaster) FileTools.openLayer(m_sFilename,
											layer.getName(), layer.getProjection());
				create(rasterLayer);
				rasterLayer.getGrid().setNoDataValue(layer.getNoDataValue());
				System.gc();
			}
		}

	}

	public void open() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			Grid grid = layer.getGrid();
			int iBands[] = new int[grid.getBandCount()];
			for (int i = 0; i < iBands.length; i++) {
				iBands[i] = i;
			}
			grid.clearDrawableBand();
			grid.addDrawableBands(iBands);
			grid.setAreaOfInterest(0, 0, grid.getWidth(), grid.getHeight());
		}

	}

	public void close() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			Grid grid = layer.getGrid();
			grid.free();
			grid.clearDrawableBand();
		}

	}

	public Rectangle2D getFullExtent() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			try{
				return layer.getFullExtent();
			}catch(Exception e){
				return null;
			}
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getExtent().toRectangle2D();
		}

		return null;

	}

	public GridExtent getLayerGridExtent() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			try{
				GridExtent extent = new GridExtent();
				extent.setCellSize(layer.getGrid().getXCellSize());
				extent.setXRange(layer.getMinX(), layer.getMaxX());
				extent.setYRange(layer.getMinY(), layer.getMaxY());
				return extent;
			}catch(Exception e){
				return null;
			}
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getGridExtent();
		}

		return null;

	}

	public double getLayerCellSize() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			return layer.getGrid().getXCellSize();
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			return layer.getGridExtent().getCellSize();
		}

		return 0;

	}

	public String getFilename() {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			return layer.getSource().getFiles()[0].getName();
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			return m_sFilename;
		}

		return "";

	}


	public Object getCRS() {

		return m_Projection;

	}


	public void setName(String name) {

		if (m_BaseDataObject instanceof FLyrRaster) {
			FLyrRaster layer = (FLyrRaster) m_BaseDataObject;
			layer.setName(name);
		}
		else if (m_BaseDataObject instanceof RasterMemoryDriver) {
			RasterMemoryDriver layer = (RasterMemoryDriver) m_BaseDataObject;
			layer.setName(name);
		};

	}

}
